package com.hb.exception;

import cn.hutool.crypto.CryptoException;
import com.hb.model.Result;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Log4j2
@RestControllerAdvice
public class ExceptionController {

	@ExceptionHandler(RuntimeException.class)
	public Result hasError(RuntimeException e) {
		log.error(e.getMessage(), e);
		return Result.message(HbExcetionEnum.RUN_ERROR);
	}

	@ExceptionHandler(Exception.class)
	public Result handleException(Exception e) {
		log.error(e.getMessage(), e);
		return Result.message(HbExcetionEnum.SYSTEM_ERROR);
	}

	@ExceptionHandler(HttpMessageNotReadableException.class)
	public Result httpException(HttpMessageNotReadableException e) {
		return Result.message(HbExcetionEnum.JSON_EXCEPTION);
	}

	@ExceptionHandler(MethodArgumentTypeMismatchException.class)
	public Result typeMismatchException(MethodArgumentTypeMismatchException ex) {
		return Result.message(HbExcetionEnum.TYPE_MISMATCH);
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public Result valid(ConstraintViolationException ex) {
		Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
		List<String> messages = constraintViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
		String message = StringUtils.collectionToDelimitedString(messages, "&&");
		return Result.message(4002, message);
	}

	@ExceptionHandler(value = BindException.class)
	public Result handleBindException(BindException ex) {
		List<String> defaultMsg = ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
		String message = StringUtils.collectionToDelimitedString(defaultMsg, "&&");
		return Result.message(4003, message);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public Result notValidException(MethodArgumentNotValidException ex) {
		List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
		List<String> defauleMessage = allErrors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
		String message = StringUtils.collectionToDelimitedString(defauleMessage, "&&");
		return Result.message(4004, message);
	}

	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public Result notSupportedException(HttpRequestMethodNotSupportedException ex) {
		return Result.message(HbExcetionEnum.REQUEST_TYPE_ERROR);
	}

	@ExceptionHandler(CryptoException.class)
	public Result cryptoException(CryptoException ex) {
		return Result.message(HbExcetionEnum.CRYPTO_EXCEPTION);
	}

	@ExceptionHandler(HbException.class)
	public Result hbError(HbException ex) {
		return Result.message(ex.getCode(), ex.getMsg());
	}

	@ExceptionHandler(DataIntegrityViolationException.class)
	public Result validLenth(DataIntegrityViolationException e) {
		log.error(e.getMessage(), e);
		return Result.message(HbExcetionEnum.TOO_LONG);
	}

	@ExceptionHandler(DuplicateKeyException.class)
	public Result handleDuplicateKeyException(DuplicateKeyException e) {
		log.error(e.getMessage(), e);
		return Result.message(HbExcetionEnum.IS_EXIT);
	}

	@ExceptionHandler(UnauthenticatedException.class)
	public Result shiroUnauthenticatedException(UnauthenticatedException ex){
		return Result.message(HbExcetionEnum.NOT_LOG_IN);
	}

	@ExceptionHandler(UnauthorizedException.class)
	public Result unauthorizedException(UnauthorizedException ex) {
		return Result.message(HbExcetionEnum.NO_PERMISSION);
	}

	@ExceptionHandler(IncorrectCredentialsException.class)
	public Result loginError(IncorrectCredentialsException  ex){
		return Result.message(HbExcetionEnum.WRONG_PASSWORD);
	}

}
